10장. 결합 균형
출처: 『소프트웨어 설계의 결합 균형』(블라드 코노노프 지음, 장연호 옮김, 제이펍 2026) | 공식: https://www.jpub.kr/
한 줄 요약: 설계의 목표는 결합 강도를 최소화하는 것이 아니라 모듈식 시스템을 만드는 것이다. 강도·거리·변동성 세 축을 동시에 보고 균형점을 찾아야 하며, 강하게 결합해도 되는 것은 가깝고 안정적인 것뿐이다.
학습 목표
이 장을 끝내면 다음을 할 수 있다.
- 결합의 세 차원(강도·거리·변동성)을 구분하고 각각이 설계에 미치는 영향을 설명한다.
- 안정성·변경 비용·모듈성·복잡성을 이진 논리식(XOR, AND, NOT)으로 표현한다.
- 강도×거리 조합의 네 가지 결과(높은 응집력·느슨한 결합·지역 복잡성·전역 복잡성)를 분류한다.
BALANCE = max(|STRENGTH - DISTANCE|, 10 - VOLATILITY) + 1공식을 실제 시나리오에 적용한다.- 복잡성 + 높은 변동성이 왜 가장 위험한 조합인지 설명한다.
- 낮은 변동성이 어떻게 높은 강도 또는 먼 거리가 만드는 복잡성을 상쇄하는지 설명한다.
전체 흐름도
결합의 세 축 (3D 큐브)
변동성(V)
높음 ↑
│
───────────────┼─────────────────
가까움 │ 멀리 (D)
←────────────────────────┼────────────────→
높은 응집력 │ 전역 복잡성
(강도↑ + 거리가까움) (강도↑ + 거리멀다)
│
지역 복잡성 │ 느슨한 결합
(강도↓ + 거리가까움) (강도↓ + 거리멀다)
───────────────┼─────────────────
│ (S=강도)
낮음 ↓
균형 공식 (이진):
BALANCE = (STRENGTH XOR DISTANCE) OR NOT VOLATILITY
= 모듈성이거나, 변동성이 낮거나, 둘 다
균형 공식 (숫자 척도 1~10):
BALANCE = max(|STRENGTH - DISTANCE|, 10 - VOLATILITY) + 1
■ 강도↑ + 거리가까움 = 높은 응집력 → 같이 변하면 가깝게 두어라
■ 강도↓ + 거리멀다 = 느슨한 결합 → 분리해야 하면 약하게 연결하라
■ 강도↑ + 거리멀다 = 전역 복잡성 → 최악의 조합
■ 강도↓ + 거리가까움 = 지역 복잡성 → 관련 없는 것을 억지로 묶음
0. 사전 필수 용어
| 용어 | 설명 |
|---|---|
| 통합 강도 (Integration Strength) | 두 구성요소가 얼마나 많은 지식을 공유하는가. 계약 결합(낮음)~침입 결합(높음) 스펙트럼. (7~9장) |
| 거리 (Distance) | 두 구성요소가 물리적으로 얼마나 멀리 배치됐는가. 같은 메서드 내(1) ~ 다른 회사 시스템(10). |
| 변동성 (Volatility) | 상위 구성요소가 얼마나 자주 바뀌는가. 레거시 불변(1) ~ 핵심 하위 도메인(10). |
| 모듈성 (Modularity) | 구현·진화·유지 관리가 간단한 설계 속성. 복잡성의 반대. |
| 안정성 (Stability) | 연쇄 변경이 발생할 가능성이 낮은 상태. 변동성이나 강도 중 하나가 낮으면 달성. |
| 이진 척도 | 이 장에서 개념 설명에 사용하는 단순 척도: 높음(1) / 낮음(0). |
| XOR(배타적 OR) | 둘 중 하나만 참일 때 참. 강도와 거리가 서로 반대 값을 가질 때 모듈성 달성. |
| 상위/하위 모듈 | 지식을 노출하는 쪽이 상위(upstream), 소비하는 쪽이 하위(downstream). 지식 흐름은 의존성 방향의 반대. |
1. 왜 세 차원을 함께 봐야 하는가
1~9장에서 강도(strength)·거리(distance)·변동성(volatility)을 각각 배웠다. 10장의 메시지는 단순하고 강력하다.
세 차원 중 어느 하나가 가장 중요하다고 말할 수 없다. 세 가지 모두 함께 관리해야 한다.
목표는 결합 강도를 최소화하는 것이 아니다. 에릭 에번스(Eric Evans)가 말했듯이, 일부 구성요소는 다른 구성요소보다 비즈니스적으로 더 중요하며 더 고급 엔지니어링 도구가 필요하다. 효능에는 건전한 실용주의가 필요하다. 목표는 모듈식 시스템 — 구현·진화·유지 관리가 간단한 시스템 — 을 설계하는 것이다. 이는 세 차원을 동시에 고려할 때만 달성된다.
비유 — 사람 관계로 보는 세 차원
| 관계 | 강도 | 거리 | 변동성 | 결과 |
|---|---|---|---|---|
| 부부 (같은 집) | 높음 | 가까움 | 낮음(서로 잘 앎) | 높은 응집력 — OK |
| 직장 동료 (같은 팀) | 중간 | 가까움 | 중간 | 관리 필요 |
| 외부 협력사 | 낮음 | 멀다 | 높음 | 느슨한 결합 — 약한 계약만 |
| 모르는 타회사 | 높음 | 멀다 | 높음 | 전역 복잡성 — 최악 |
부부는 강하게 결합돼도 된다 — 가깝고(같은 집), 안정적(서로를 잘 앎). 하지만 모르는 사람과 강하게 결합되면 — 멀고 + 변동성 높음 — 재앙이 된다.
비유 — 건축
같은 집 안의 가구는 강하게 배치해도 된다(가깝고, 주인의 취향이 안정적이면). 하지만 옆 건물과 내 집 벽을 강하게 고정하면 — 옆 건물이 공사를 시작하면 내 벽도 무너진다. 옆 건물과는 약한 연결(출입문, 계약)만 있어야 한다.
소프트웨어도 같다. 같은 네임스페이스의 두 클래스는 강하게 결합돼도 된다(가깝고, 변동이 함께 일어남). 다른 회사 시스템과 강하게 결합하면 — 상대가 API 하나 바꿀 때마다 내 시스템이 흔들린다.
2. 차원 쌍별 상호작용
2.1 안정성: 변동성 × 강도
STABILITY = NOT (VOLATILITY AND STRENGTH)
변동성과 강도 둘 다 높을 때만 불안정하다. 둘 중 하나가 낮으면 안정적이다.
| 변동성 | 강도 | 안정성 | 이유 |
|---|---|---|---|
| 낮음 | 낮음 | 안정적 | 변경도 없고, 전파도 안 됨 |
| 낮음 | 높음 | 안정적 | 바뀔 일이 없으므로 강도는 문제 아님 |
| 높음 | 낮음 | 안정적 | 자주 바뀌지만, 낮은 강도가 전파 차단 |
| 높음 | 높음 | 불안정 | 자주 바뀌고, 전파도 잘 됨 |
비유 — 전화선과 진동: 강도는 전화선의 굵기, 변동성은 전화선 양쪽에서 발생하는 지진의 빈도다. 선이 굵을수록 진동이 잘 전달된다. 진동이 드물면 굵은 선도 별 문제 없다. 진동이 잦고 선도 굵으면 — 맞은편이 흔들릴 때마다 내 쪽도 흔들린다.
2.2 실제 변경 비용: 변동성 × 거리
CHANGES COST = VOLATILITY AND DISTANCE
변동성과 거리 둘 다 높을 때 실제 비용이 최대가 된다.
| 변동성 | 거리 | 변경 비용 | 이유 |
|---|---|---|---|
| 낮음 | 가까움 | 낮음 | 둘 다 낮음 |
| 낮음 | 멀다 | 낮음 | 자주 안 바뀌므로 |
| 높음 | 가까움 | 낮음 | 가깝게 두었으므로 조정 쉬움 |
| 높음 | 멀다 | 높음 | 자주 바뀌고, 멀리 있는 팀과 협업해야 함 |
비유 — 택배와 이삿짐: 이삿짐이 자주 바뀌지 않으면(낮은 변동성) 창고가 멀어도 큰 문제 없다. 이삿짐이 매일 바뀌는데 창고가 서울-부산 거리면 — 매일 택배비와 배송 시간이 든다. 변동성을 낮추거나 창고를 가까이 두거나, 둘 중 하나로 해결해야 한다.
2.3 모듈성과 복잡성: 강도 × 거리
이 조합이 책의 핵심 통찰이다.
MODULARITY = STRENGTH XOR DISTANCE
COMPLEXITY = NOT MODULARITY = NOT (STRENGTH XOR DISTANCE)
LOCAL COMPLEXITY = NOT STRENGTH AND NOT DISTANCE
GLOBAL COMPLEXITY = STRENGTH AND DISTANCE
강도와 거리가 반대 값일 때 모듈성이 달성된다.
| 강도 | 거리 | 결과 | 비고 |
|---|---|---|---|
| 낮음 | 가까움 | 지역 복잡성 | 관련 없는 것을 가까이 묶음 |
| 높음 | 가까움 | 높은 응집력 | 같이 변하는 것이 가까이 있음 |
| 낮음 | 멀다 | 느슨한 결합 | 분리된 것끼리 약하게 연결 |
| 높음 | 멀다 | 전역 복잡성 | 멀리 있는데 강하게 결합 — 최악 |
핵심 통찰: 강도와 거리는 짝꿍이어야 한다. 강하게 결합할 거면 가까이 두어라. 멀리 떼어 놓을 거면 약하게 연결하라. 두 값이 같을 때(둘 다 높거나 둘 다 낮을 때) 복잡성으로 기운다.
3. 코드 예제
잘못된 예 — 전역 복잡성 (강도↑ + 거리↑)
# WolfDesk 사례: 두 마이크로서비스(거리=9)에 동일한 비즈니스 로직 복제 (대칭적 기능 결합=9)
# 잘못된 예: 분산 서비스에 핵심 비즈니스 로직을 직접 복제
# support_cases_service/escalation.py
def can_escalate(case):
return case.priority >= 3 and case.age_hours >= 24 # 비즈니스 규칙
# distribution_service/escalation.py (다른 서비스에 복제!)
def can_escalate(case):
return case.priority >= 3 and case.age_hours >= 24 # 동일 규칙 복제
# 문제: 규칙 변경 시 두 서비스를 동시에 업데이트해야 함
# 강도(9) × 거리(9) → 전역 복잡성, BALANCE = max(|9-9|, 10-10)+1 = 1 (최악)
올바른 예 — 느슨한 결합 (강도↓ + 거리↑)
# 올바른 예: 비즈니스 규칙을 한 서비스에 두고, 계약(API)으로만 연결
# support_cases_service/api.py
@app.get("/cases/{case_id}/can-escalate")
def can_escalate_endpoint(case_id: str):
case = case_repo.get(case_id)
return {"result": case.priority >= 3 and case.age_hours >= 24}
# distribution_service/client.py
class EscalationClient:
def can_escalate(self, case_id: str) -> bool:
return requests.get(f"{BASE_URL}/cases/{case_id}/can-escalate").json()["result"]
# 거리(9)이지만 강도(1=계약 결합) → BALANCE = max(|1-9|, 10-10)+1 = max(8,0)+1 = 9 (거의 최상)
올바른 예 — 높은 응집력 (강도↑ + 거리↓)
# 같은 네임스페이스 안에서 강하게 결합 — 거리가 가깝기 때문에 OK
# support_cases_service/models.py
class SupportCase:
def __init__(self, case_id, priority, age_hours):
self.case_id = case_id
self.priority = priority
self.age_hours = age_hours
class Message:
def __init__(self, case: SupportCase, content: str):
self.case = case # 강한 기능 결합(8) — 같은 트랜잭션 필요
self.content = content
def save_with_case(self, session):
session.add(self.case) # 같은 트랜잭션 커밋
session.add(self)
session.commit()
# 강도(8) × 거리(2=같은 네임스페이스) → 높은 응집력
# BALANCE = max(|8-2|, 10-10)+1 = max(6,0)+1 = 7 (양호)
잘못된 예 — 변동성 높은 상위에 강하게 결합
# 잘못된 예: 자주 바뀌는 핵심 비즈니스 로직(변동성=10)을 다른 팀 서비스(거리=8)가 모델 공유
# billing_service/client.py
from support_cases_service.models import SupportCase # 내부 모델 직접 임포트
class BillingService:
def calculate_fee(self, case: SupportCase) -> float:
return case.priority * case.age_hours * 0.01 # SupportCase 내부 필드를 직접 사용
# 문제: SupportCase 내부 구조가 바뀌면(핵심 하위 도메인이라 자주 바뀜) BillingService도 깨짐
# 강도(7=모델 결합) + 거리(8=다른 라이브러리) + 변동성(10) → BALANCE 낮음
올바른 예 — 계약 결합으로 내부 모델 캡슐화
# 올바른 예: 계약(API)으로만 연결 — 내부 모델을 외부에 노출하지 않음
# support_cases_service/api.py
@app.get("/cases/{case_id}/billing-info")
def get_billing_info(case_id: str):
case = case_repo.get(case_id)
# 외부에 필요한 것만, 내부 구조는 숨김
return {"priority": case.priority, "age_hours": case.age_hours}
# billing_service/client.py
class BillingClient:
def get_billing_info(self, case_id: str) -> dict:
return requests.get(f"{BASE_URL}/cases/{case_id}/billing-info").json()
class BillingService:
def calculate_fee(self, case_id: str) -> float:
info = self.client.get_billing_info(case_id)
return info["priority"] * info["age_hours"] * 0.01
# 강도(1=계약 결합) + 거리(8) → |1-8|=7 → BALANCE 높음
4. 세 차원을 모두 합치기 — 균형 방정식
4.1 유지 관리 노력
MAINTENANCE EFFORT = STRENGTH × DISTANCE × VOLATILITY
세 차원의 곱이 유지 관리 고통을 나타낸다. 하나라도 0이면 전체가 0이 된다 — 하나만 낮게 유지하면 나머지가 높아도 된다.
| 시나리오 | 강도 | 거리 | 변동성 | 유지 관리 노력 |
|---|---|---|---|---|
| 느슨한 결합 | 낮음 | 멀다 | 높음 | 낮음 (강도가 0을 만듦) |
| 높은 응집력 | 높음 | 가까움 | 높음 | 낮음 (거리가 0을 만듦) |
| 레거시 통합 | 높음 | 멀다 | 낮음 | 낮음 (변동성이 0을 만듦) |
| 최악 | 높음 | 멀다 | 높음 | 높음 (세 곱이 모두 높음) |
주의: 유지 관리 노력 공식은 더 높은 수준의 사각지대가 있다. 낮은 강도 + 가까운 거리 + 높은 변동성 조합에서 지역 복잡성의 문제를 포착하지 못한다. 이를 위해 균형 잡힌 결합 개념이 필요하다.
4.2 균형 잡힌 결합
두 가지 나쁜 조합이 있다.
전역 복잡성 + 높은 변동성: 강도↑ + 거리↑ + 변동성↑ ← 최악
지역 복잡성 + 높은 변동성: 강도↓ + 거리가까움 + 변동성↑ ← 나쁨
이진 논리로 균형을 표현하면:
BALANCE = NOT (COMPLEXITY AND VOLATILITY)
= MODULARITY OR NOT VOLATILITY
= (STRENGTH XOR DISTANCE) OR NOT VOLATILITY
풀어 읽기: 균형은 모듈성이 있거나, 변동성이 낮거나, 둘 중 하나이면 된다. 복잡성 + 높은 변동성이 동시에 존재할 때만 진짜 위험하다.
4.3 숫자 척도로 균형 계산
책이 제안하는 임의 척도 (1~10):
| 차원 | 1 | 10 |
|---|---|---|
| 통합 강도 | 계약 결합 | 침입 결합 |
| 거리 | 같은 객체 메서드 | 다른 회사 시스템 |
| 변동성 | 진화 없는 레거시 | 핵심 하위 도메인 |
거리 세부 기준: - 1: 동일한 객체의 메서드 - 2: 동일한 네임스페이스/패키지의 객체 - 3~7: 다른 네임스페이스/패키지의 객체 - 8: 다른 라이브러리 - 9: 분산 시스템의 서비스 - 10: 다른 공급업체가 구현한 시스템
모듈성 점수: MODULARITY = |STRENGTH - DISTANCE| + 1
강도와 거리의 차이가 클수록(서로 반대 값일수록) 모듈성이 높다.
균형 점수: BALANCE = max(|STRENGTH - DISTANCE|, 10 - VOLATILITY) + 1
모듈성이 낮더라도 변동성이 충분히 낮으면 균형이 높아진다. 낮은 변동성이 복잡성을 상쇄한다.
주의사항: 이것은 정확한 과학이 아니다. 책 저자 본인이 강조한다. 척도와 범위는 팀에 맞게 조정하라. 중요한 것은 숫자 자체가 아니라 세 차원이 어떻게 함께 작동하는지 이해하는 것이다.
5. 실제 시나리오 4가지 — WolfDesk 예제
예제 1: ML 서비스 통합 (균형 점수 8 → 10)
WolfDesk의 Support Cases Management(핵심 하위 도메인)가 외부 클라우드 ML 서비스에 운영 DB 데이터를 직접 공급하는 경우.
강도(S) = 3 (모델 결합 — DB 스키마 공유)
거리(D) = 10 (다른 회사 시스템)
변동성(V) = 10 (핵심 하위 도메인)
BALANCE = max(|3-10|, 10-10) + 1
= max(7, 0) + 1 = 8
계약 결합(S=1)으로 개선하면:
BALANCE = max(|1-10|, 10-10) + 1 = max(9, 0) + 1 = 10 (완벽)
교훈: 거리가 멀수록 강도를 더 낮춰야 균형 점수가 올라간다.
예제 2: 같은 모듈 내 두 객체 (균형 점수 7)
Support Cases Management 안의 SupportCase와 Message — 같은 트랜잭션 커밋 필요.
강도(S) = 8 (기능 결합 — 트랜잭션 공유)
거리(D) = 2 (같은 네임스페이스)
변동성(V) = 10 (핵심 하위 도메인)
BALANCE = max(|8-2|, 10-10) + 1
= max(6, 0) + 1 = 7
→ 양호. 강도가 높지만 거리가 가깝기 때문에 균형.
교훈: 비즈니스 요구상 강하게 결합해야 한다면, 가까이 두어라(높은 응집력).
예제 3: 마이크로서비스 간 비즈니스 로직 복제 (균형 점수 1 — 최악)
두 서비스에 동일한 에스컬레이션 규칙을 복제.
강도(S) = 9 (대칭적 기능 결합 — 동일 알고리즘 복제)
거리(D) = 9 (분산 시스템의 두 서비스)
변동성(V) = 10 (핵심 하위 도메인)
BALANCE = max(|9-9|, 10-10) + 1
= max(0, 0) + 1 = 1 (최악)
교훈: 강도 = 거리인 경우 모듈성이 0이 된다. 복잡성 + 높은 변동성 = 최악의 조합.
예제 4: 레거시 시스템 침입 통합 (균형 점수 10)
새 마이크로서비스가 레거시 시스템의 DB에 직접 접근 — 하지만 레거시는 더 이상 변경되지 않는다.
강도(S) = 10 (침입 결합 — 비공개 인터페이스 접근)
거리(D) = 9 (같은 회사의 다른 시스템)
변동성(V) = 1 (진화하지 않는 레거시)
BALANCE = max(|10-9|, 10-1) + 1
= max(1, 9) + 1 = 10 (완벽)
교훈: 낮은 변동성이 높은 강도와 먼 거리를 완전히 상쇄한다. "항상 강한 결합은 나쁘다"가 아니다 — 상위가 변하지 않으면 강하게 의존해도 유지 관리 비용이 낮다.
6. 안티패턴
안티패턴 1: 전역 복잡성 + 높은 변동성 (최악)
강도↑ + 거리↑ + 변동성↑
신호:
- 자주 바뀌는 핵심 비즈니스 로직을 다른 회사/팀 서비스와 강하게 결합
- 마이크로서비스 간 DB 직접 공유 + 해당 스키마가 자주 변경됨
- 외부 파트너와 내부 구현 세부(침입 결합)로 통합
처방: 계약 결합(강도↓)으로 바꾸거나, 상위를 안정화(변동성↓)하거나, 가까이 배치(거리↓)하라.
안티패턴 2: 지역 복잡성 + 높은 변동성
강도↓ + 거리가까움 + 변동성↑
신호:
- 서로 관련 없는 기능이 같은 클래스/패키지에 모여 있음
- 파일이 자주 바뀌는데 그 안에 연관 없는 코드가 섞여 있음
- "한 파일에 다 넣어 두는" 스타일
처방: 관련 없는 구성요소를 분리하라(거리↑). 가까이 있어야 하는 것만 가까이 두어라.
7. 실무 결정 매트릭스
| 상황 | 권장 전략 | 이유 |
|---|---|---|
| 같은 팀, 같은 배포, 함께 변경 | 강하게 결합 + 가깝게 배치 | 높은 응집력 — 자연스러운 공생 |
| 다른 팀, 자주 변경되는 상위 | 계약 결합(약하게) + 멀리 | 느슨한 결합 — 변경 격리 |
| 외부 파트너, 안정적(변경 없음) | 강도 타협 가능 | 낮은 변동성이 강도 상쇄 |
| 레거시 통합(불변) | 침입도 OK | 변동성=1이 모든 걸 상쇄 |
| 핵심 하위 도메인 간 분리 | 반드시 계약 결합 | 양쪽 모두 변동성 높아 위험 |
핵심 개념 정리
| 개념 | 한 줄 설명 |
|---|---|
| 결합의 세 차원 | 강도(얼마나 많이 앎) + 거리(얼마나 멀리) + 변동성(얼마나 자주 변함) |
| 안정성 | NOT (VOLATILITY AND STRENGTH) — 둘 중 하나만 낮아도 안정 |
| 변경 비용 | VOLATILITY AND DISTANCE — 둘 다 높을 때만 비쌈 |
| 모듈성 | STRENGTH XOR DISTANCE — 서로 반대 값일 때 달성 |
| 균형 (이진) | (STRENGTH XOR DISTANCE) OR NOT VOLATILITY |
| 균형 (숫자) | BALANCE = max(|S-D|, 10-V) + 1 (1~10 척도) |
| 높은 응집력 | 강도↑ + 거리가까움 — 같이 변할 것을 가까이 둠 |
| 느슨한 결합 | 강도↓ + 거리멀다 — 분리된 것끼리 약하게 연결 |
| 전역 복잡성 | 강도↑ + 거리↑ — 가장 위험한 조합 |
| 지역 복잡성 | 강도↓ + 거리가까움 — 관련 없는 것을 강제로 묶음 |
| 유지 관리 노력 | STRENGTH × DISTANCE × VOLATILITY — 하나만 0이면 전체 0 |
| 낮은 변동성의 힘 | 복잡성도 상쇄 가능 — 레거시 침입 통합 예제 |
| 에릭 에번스의 실용주의 | 목표는 강도 최소화가 아닌 모듈식 시스템 — 건전한 실용주의 필요 |
실무 체크리스트
- [ ] 새 통합을 설계할 때 강도·거리·변동성 세 가지 모두를 명시적으로 평가했는가?
- [ ] 강도가 높다면 거리가 가까운가? (높은 응집력 보장)
- [ ] 거리가 멀다면 강도가 낮은가? (느슨한 결합 보장)
- [ ] 변동성이 높은 상위에 강하게 결합하고 있지 않은가? (안정성 확인)
- [ ] 외부 파트너나 다른 팀 서비스와 통합할 때 계약 결합을 사용하고 있는가?
- [ ] 레거시 시스템 통합 시 변동성을 먼저 평가했는가? (낮으면 강도 타협 가능)
- [ ] 마이크로서비스 간에 동일한 비즈니스 로직을 복제하고 있지 않은가? (대칭적 기능 결합 경고)
- [ ]
BALANCE = max(|S-D|, 10-V) + 1점수가 낮은 통합을 식별하고 개선 계획이 있는가? - [ ] "강도를 무조건 낮추자"가 목표가 아니라 "모듈식 시스템"이 목표임을 팀이 공유하고 있는가?
- [ ] 유지 관리 노력 공식의 사각지대(지역 복잡성)도 별도로 점검했는가?
연습문제 (정답은 부록 D)
-
공식 적용. 다음 시나리오의 균형 점수를 계산하라.
강도=5(모델 결합), 거리=5(다른 패키지의 서비스), 변동성=8(핵심 하위 도메인에 가까운 기능). 이 설계를 어떻게 개선할 수 있는가? -
분류. 다음 네 가지 조합을 "높은 응집력 / 느슨한 결합 / 지역 복잡성 / 전역 복잡성" 중 하나로 분류하고, 각각이 왜 모듈성 또는 복잡성에 기여하는지 설명하라.
- a. 강도=낮음, 거리=가까움
- b. 강도=높음, 거리=가까움
- c. 강도=낮음, 거리=멀다
-
d. 강도=높음, 거리=멀다
-
레거시 시나리오. 팀이 레거시 시스템(10년 된 ERP, 더 이상 개발하지 않음)과 통합해야 한다. ERP는 공식 API가 없어 DB에 직접 접근할 수밖에 없다. 이 결합의 균형 점수를 계산하고, 이 방식이 받아들일 만한지 판단하라.
-
안티패턴 진단. 현재 팀의 코드베이스에서 "전역 복잡성" 안티패턴의 신호를 세 가지 찾는 방법을 설명하라. 어떤 파일·경로·통합 패턴을 먼저 살펴보겠는가?
-
설계 결정. 스타트업이 자사의 핵심 추천 알고리즘(매일 바뀌는 핵심 하위 도메인)을 외부 ML 플랫폼(다른 회사)과 통합하려 한다. 두 가지 방안을 비교하라. a) ML 플랫폼이 내부 DB를 직접 읽음, b) 공식 데이터 내보내기 API를 통해 데이터 공급. 각 방안의 균형 점수를 추정하고 권장 방안을 제시하라.
최신 동향 (검증 2026-05-21)
- 모듈 모놀리스 재조명: 분산 시스템에서 거리를 늘렸을 때 강도를 낮추지 않아 전역 복잡성이 발생하는 사례가 누적되면서, 모듈 모놀리스(Modular Monolith) — 논리적으로 분리되나 배포는 하나 — 접근법이 재조명받고 있다. Sam Newman이 마이크로서비스 분리 전 모듈 경계를 먼저 정의할 것을 강조한다. samnewman.io
- 진화적 아키텍처와 피트니스 함수: Neal Ford·Rebecca Parsons 등이 강조하는 핵심 원칙이 "변동성에 맞춰 결합 강도를 적응시키는 것"이다. 피트니스 함수(fitness function)로 결합 지표를 지속 측정해 균형 이탈을 자동 감지하는 방향으로 발전 중이다. evolutionaryarchitecture.io
- 결합 측정 도구화: 정적 분석 도구들이 모듈 간 의존성 강도와 거리를 자동 측정하는 기능을 강화하고 있다. 저자가 미래에 기대한 자동화 평가 도구가 점진적으로 실현되는 추세다.
부록 A. 용어 사전
| 한글 용어 | 원문 영문명 | 의미 |
|---|---|---|
| 강도 | Integration Strength | 두 구성요소가 공유하는 지식의 양. 계약 결합(낮음)~침입 결합(높음) |
| 거리 | Distance | 구성요소 간 물리적 배치 거리. 같은 메서드(1)~다른 회사(10) |
| 변동성 | Volatility | 상위 구성요소가 변경되는 빈도. 레거시(1)~핵심 하위 도메인(10) |
| 모듈성 | Modularity | 구현·진화·유지 관리가 간단한 설계 속성 |
| 복잡성 | Complexity | 모듈성의 반대. 지역(강도↓+거리가까움) 또는 전역(강도↑+거리↑) |
| 안정성 | Stability | 연쇄 변경 가능성이 낮은 상태. NOT(변동성 AND 강도) |
| 균형 | Balance | 강도·거리·변동성 세 차원의 종합 설계 품질. 1~10 점수 |
| 유지 관리 노력 | Maintenance Effort | 통합 유지에 필요한 예상 노력. 강도×거리×변동성 |
| 높은 응집력 | High Cohesion | 강도↑+거리가까움 — 같이 변할 것이 가까이 있음 |
| 느슨한 결합 | Loose Coupling | 강도↓+거리↑ — 분리된 것끼리 약하게 연결 |
| 전역 복잡성 | Global Complexity | 강도↑+거리↑ — 가장 위험한 결합 조합 |
| 지역 복잡성 | Local Complexity | 강도↓+거리가까움 — 관련 없는 것을 가까이 묶음 |
| XOR | Exclusive OR | 둘 중 하나만 참일 때 참. 강도와 거리가 반대 값일 때 모듈성 |
| 상위 모듈 | Upstream Module | 지식을 노출하는 쪽. 지식 흐름 방향의 출발점 |
| 하위 모듈 | Downstream Module | 지식을 소비하는 쪽. 상위에 의존하는 소비자 |
부록 B. 핵심 비교표
강도 × 거리 조합의 네 가지 결과
| 강도 | 거리 | 결과 | 비유 | 권장 여부 |
|---|---|---|---|---|
| 높음 | 가까움 | 높은 응집력 | 부부 — 강하게 결합, 가까이 삶 | 권장 (함께 변할 것) |
| 낮음 | 멀다 | 느슨한 결합 | 계약서로만 만나는 파트너 | 권장 (분리할 것) |
| 낮음 | 가까움 | 지역 복잡성 | 억지로 같은 방에 모인 타인들 | 비권장 (분리하라) |
| 높음 | 멀다 | 전역 복잡성 | 서울-부산에 사는데 매일 이사 | 최악 — 반드시 개선 |
숫자 척도 기준표
| 값 | 통합 강도 | 거리 | 변동성 |
|---|---|---|---|
| 1 | 계약 결합 | 같은 객체 메서드 | 불변 레거시 |
| 2~3 | 모델 결합 | 같은 네임스페이스 | 지원 하위 도메인 |
| 8~9 | 기능/대칭 결합 | 분산 서비스 | 중요 도메인 |
| 10 | 침입 결합 | 다른 회사 시스템 | 핵심 하위 도메인 |
WolfDesk 예제 균형 점수 요약
| 예제 | 강도 | 거리 | 변동성 | BALANCE | 평가 |
|---|---|---|---|---|---|
| ML 서비스 통합 (모델 결합) | 3 | 10 | 10 | 8 | 양호 |
| ML 서비스 통합 (계약 결합) | 1 | 10 | 10 | 10 | 최상 |
| SupportCase-Message (같은 모듈) | 8 | 2 | 10 | 7 | 양호 |
| 마이크로서비스 로직 복제 | 9 | 9 | 10 | 1 | 최악 |
| 레거시 침입 통합 | 10 | 9 | 1 | 10 | 최상 (변동성 덕분) |
부록 C. 추천 참고 자료 & 링크
| 자료 | 링크 |
|---|---|
| 책 공식 (제이펍) | jpub.kr |
| 원서 — Manning | Balancing Coupling in Software Design |
| 진화적 아키텍처 (Ford·Parsons) | evolutionaryarchitecture.io |
| Sam Newman — Building Microservices 2nd | samnewman.io |
| 마이크로서비스 패턴 (Chris Richardson) | microservices.io/patterns |
책 다른 장 안내
| 장 | 설명 |
|---|---|
| 1장 | 결합의 정의 — 강도의 두 동인(공유 수명주기·공유 지식) |
| 4장 | 모듈성 — 결합의 반대편 |
| 7~9장 | 통합 강도 모델 (계약~침입 결합 스펙트럼) |
| 11장 | 시간이 지나도 모듈성 유지하기 — 진화 |
| 12장 | 소프트웨어 설계의 프랙털 기하학 |
부록 D. 연습문제 풀이
-
(균형 점수 계산 및 개선)
BALANCE = max(|5-5|, 10-8) + 1 = max(0, 2) + 1 = 3. 매우 낮은 점수 — 강도와 거리가 같아 모듈성이 0이고, 변동성도 높다. 개선 방법: ① 강도를 낮춘다(계약 결합 S=1) →max(|1-5|, 2)+1 = max(4,2)+1 = 5. ② 거리를 좁힌다(같은 패키지 D=2) →max(|5-2|, 2)+1 = max(3,2)+1 = 4. 가장 좋은 방법은 강도를 대폭 낮추거나(계약 결합), 변동성을 낮추는 것(안정화 또는 안정적 인터페이스 분리). -
(분류)
- a. 강도=낮음, 거리=가까움 → 지역 복잡성. 관련 없는 구성요소를 가까이 묶어 탐색 부하 증가. 변경 시 무관한 코드를 살펴봐야 함.
- b. 강도=높음, 거리=가까움 → 높은 응집력. 같이 변해야 하는 구성요소가 가까이 있어 변경 구현 비용 낮음. 모듈성에 기여.
- c. 강도=낮음, 거리=멀다 → 느슨한 결합. 분리된 구성요소끼리 최소 계약으로 연결. 변경이 전파되지 않아 모듈성에 기여.
-
d. 강도=높음, 거리=멀다 → 전역 복잡성. 멀리 있는데 강하게 결합 — 변경 전파 비용 최대, 인지 부하 최대. 가장 위험.
-
(레거시 시나리오) 레거시 ERP는 더 이상 진화하지 않으므로
변동성(V) = 1. DB 직접 접근이므로강도(S) = 10(침입 결합). 같은 회사 시스템이면거리(D) = 9.BALANCE = max(|10-9|, 10-1)+1 = max(1, 9)+1 = 10. 받아들일 만하다 — 낮은 변동성(1)이 침입 결합과 먼 거리를 완전히 상쇄한다. 단, 레거시가 언젠가 마이그레이션될 계획이라면 그 시점의 변동성을 다시 평가해야 한다. -
(전역 복잡성 신호 찾기) 다음을 먼저 살펴보라: ① 서비스 간 직접 DB 접근 — 다른 서비스의 DB를 직접 SELECT하는 코드. 마이크로서비스라면 절대 없어야 함(강도↑+거리↑). ② 양방향 의존성 — 서비스 A가 B를 호출하고, B도 A를 호출하는 순환 의존. 두 서비스가 서로의 내부를 안다는 신호. ③ 분산 서비스에 복제된 비즈니스 로직 — 동일한 조건식이나 알고리즘이 두 서비스에 복사되어 있음. 한쪽 변경 시 다른 쪽도 바꿔야 하는 대칭적 기능 결합.
-
(설계 결정 비교) a안: ML 플랫폼이 내부 DB 직접 읽음 —
강도(S)=5(모델 결합), 거리(D)=10(다른 회사), 변동성(V)=10(핵심 알고리즘)→BALANCE = max(|5-10|, 10-10)+1 = max(5,0)+1 = 6. 보통. b안: 공식 데이터 내보내기 API —강도(S)=1(계약 결합), 거리(D)=10, 변동성(V)=10→BALANCE = max(|1-10|, 10-10)+1 = max(9,0)+1 = 10. 최상. 권장: b안. 핵심 하위 도메인(변동성=10)의 내부 모델을 외부에 노출하면 알고리즘이 바뀔 때마다 외부 파트너도 영향을 받는다. 계약 결합으로 내부 모델 변경을 캡슐화하는 것이 필수.
클릭하거나 Space를 눌러 뒤집기